package com.jeecg.p3.system.order.service;

import com.jeecg.p3.base.util.*;
import com.jeecg.p3.commonweixin.def.CommonWeixinProperties;
import com.jeecg.p3.system.order.dao.CourseOrderDao;
import com.jeecg.p3.system.order.dao.ProductDetailsDao;
import com.jeecg.p3.system.order.entity.CourseOrder;
import com.jeecg.p3.system.order.entity.F2FQueryVo;
import com.jeecg.p3.system.order.entity.JsapiResultVo;
import com.jeecg.p3.system.order.entity.ProductDetails;
import com.jeecg.p3.system.order.web.JsapiPayController;
import com.jeecg.p3.system.poster.dao.CustomerCouponDao;
import com.jeecg.p3.system.poster.dao.PosterManagerDao;
import com.jeecg.p3.system.poster.entity.CustomerCoupon;
import com.jeecg.p3.system.poster.entity.PosterManager;
import org.dom4j.DocumentException;
import org.jeecgframework.p3.core.utils.common.PageList;
import org.jeecgframework.p3.core.utils.common.PageQuery;
import org.jeecgframework.p3.core.utils.common.PageQueryWrapper;
import org.jeecgframework.p3.core.utils.common.Pagenation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.jeecg.p3.base.util.DateUtil.DATETIME_PATTERN;
import static com.jeecg.p3.base.util.PayUtils.getSign;
import static com.jeecg.p3.base.util.PayUtils.getnonceStr;
import static com.jeecg.p3.base.util.PayUtils.mapToXml;

/**
 *
 * @ClassName: CourseOrderService
 * @Description: TODO 订单管理处理层
 * @author: lzx
 * @date: 2020年12月01日 下午7:29:38
 */
@Service
public class CourseOrderService {

    private static final Logger log = LoggerFactory.getLogger(CourseOrderService.class);

    @Resource
    private CourseOrderDao dao;
    @Resource
    private ProductDetailsDao productDetailsDao;
    @Resource
    private CustomerCouponDao customerCouponDao;

    /**
     * 分页查询订单管理信息
     * @param pageQuery
     * @return
     */
    public PageList<CourseOrder> queryPageList(PageQuery<CourseOrder> pageQuery) {
        PageList<CourseOrder> result = new PageList<>();
        Integer itemCount = dao.count(pageQuery);
        PageQueryWrapper<CourseOrder> wrapper = new PageQueryWrapper<>(pageQuery.getPageNo(), pageQuery.getPageSize(),itemCount, pageQuery.getQuery());
        List<CourseOrder> list = dao.queryPageList(wrapper);
        Pagenation pagenation = new Pagenation(pageQuery.getPageNo(), itemCount, pageQuery.getPageSize());
        result.setPagenation(pagenation);
        result.setValues(list);
        return result;
    }

    /**
     * 根据条件查询业绩总额
     * @param pageQuery
     * @return
     */
    public List<Map<String, Object>> findCountByParam(PageQuery<CourseOrder> pageQuery) {
        return dao.findCountByParam(pageQuery);
    }

    /**
     * 新增订单管理信息1
     * @param
     */
    public CourseOrder doAdd(String userName,String money,String productId,String openId,String couponId, String wxPhoto) {
        CourseOrder courseOrder=new CourseOrder();
        String order = RandomUtil.getAppId();//订单号
        courseOrder.setCreateDate(DateUtil.dateToString(new Date()));
        courseOrder.setCreateTime(DateUtil.dateToString(new Date(), "HH:mm:ss"));
        courseOrder.setStatus(ComCode.statusNormal);
        courseOrder.setPayStatus(0);//初始支付状态为0  未支付
        courseOrder.setUserName(userName);
        courseOrder.setTotalMoney(money);
        courseOrder.setProductId(productId);
        courseOrder.setDataLsh(order);
        courseOrder.setOpenId(openId);
        courseOrder.setWxPhoto(wxPhoto);
        courseOrder.setCouponId(couponId);
        dao.insert(courseOrder);
        return courseOrder;
    }

    /**
     * 根据参数获取订单管理信息数量
     * @param courseOrder
     * @return
     */
    public Integer count(CourseOrder courseOrder) {
        PageQuery<CourseOrder> pageQuery = new PageQuery<>();
        pageQuery.setQuery(courseOrder);
        return dao.count(pageQuery);
    }

    /**
     * 根据id查询订单管理信息
     * @param id
     * @return
     */
    public CourseOrder findById(Long id) {
        return dao.get(id);
    }

    /**
     * 根据传参获取订单管理列表信息
     * @param courseOrder
     * @return
     */
    public List<CourseOrder> findByParam(CourseOrder courseOrder) {
        return dao.findByParam(courseOrder);
    }


    /**
     * 根据订单号查询订单信息
     * @param
     * @return
     */
    public CourseOrder findByNo(String dataLsh) {
        return dao.findByNo(dataLsh);
    }
    /**
     * 编辑订单管理信息
     * @param courseOrder
     */
    public void doEdit(CourseOrder courseOrder) {
        dao.update(courseOrder);
    }

    /**
     * 删除订单管理信息
     * @param courseOrder
     */
    public void doDelete(CourseOrder courseOrder) {
        courseOrder.setStatus("0");
        dao.update(courseOrder);
    }

    /**
     * 微信公众号支付预支付生成订单，返回支付实体对象
     * @param
     * @param
     * @return
     */
    public JsapiResultVo getJsapiPayResultVo(String orderNo, String orderPrice, String open_id ) {
        JsapiResultVo jsapiResultVo=new JsapiResultVo();
        //String money = detail.getMoney();
        try {
            BigDecimal amount=new BigDecimal(orderPrice);
            //预支付下单，微信公众号支付返回应答参数
            Map<String, Object> wxResultMap =weiXinJsapiOrder(orderNo,amount,open_id);
            String prepay_id = wxResultMap.get("package").toString();
            String appid = wxResultMap.get("appId").toString();
            String timeStamp = wxResultMap.get("timeStamp").toString();
            String nonceStr = wxResultMap.get("nonceStr").toString();
            String signType = wxResultMap.get("signType").toString();
            String paySign = wxResultMap.get("paySign").toString();

            jsapiResultVo.setAppid(appid);
            jsapiResultVo.setPrepay_id(prepay_id);
            jsapiResultVo.setTimeStamp(timeStamp);
            jsapiResultVo.setNonce_str(nonceStr);
            jsapiResultVo.setSign(paySign);
            jsapiResultVo.setTrade_type(signType);
            jsapiResultVo.setOrderNo(orderNo);
            if(prepay_id!=null){
                jsapiResultVo.setReturn_code("SUCCESS");
                jsapiResultVo.setReturn_msg("ok");
            }else{
                jsapiResultVo.setReturn_code("FAILED");
                jsapiResultVo.setReturn_msg("fail");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.debug(orderPrice,orderNo,open_id);
        }
        System.out.println("jsapiResultVo:" + jsapiResultVo.toString());
        return jsapiResultVo;
    }

    /**
     * 微信公众号支付下单接口
     * @param out_trade_no
     * @param totalAmount
     * @param open_id
     * @return
     */
    public static Map weiXinJsapiOrder(String out_trade_no, BigDecimal totalAmount ,String open_id) {
        //拼接统一下单地址参数
        SortedMap<String, Object> paraMap = new TreeMap<>();
        //获取请求ip地址
        InetAddress ia = null;
        try {
            ia = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        //微信支付金额不能带小数点，金额扩大为100
        Integer total_fee = totalAmount.multiply(BigDecimal.valueOf(100L)).intValue();

        String localip = ia.getHostAddress();
        paraMap.put("appid", CommonWeixinProperties.component_appid);
        paraMap.put("mch_id", CommonWeixinProperties.MCHID);
        //paraMap.put("sub_mch_id",WeixinConfigUtil.sub_mch_id);//服务商模式传入子商户号
        paraMap.put("nonce_str", getnonceStr());
        paraMap.put("body", "大医国脉");
        paraMap.put("out_trade_no", out_trade_no);//订单号
        paraMap.put("total_fee", total_fee);//订单金额
        paraMap.put("spbill_create_ip", localip);
        paraMap.put("notify_url",CommonWeixinProperties.backUrl);// 此路径是微信服务器调用支付结果通知路径
        paraMap.put("trade_type", "JSAPI");

        paraMap.put("openid",open_id);//用户标识 obAkm1kao1fnbIuM61jXOFCxobhE
        String sign = getSign(paraMap, CommonWeixinProperties.PARTNER_KEY);
        paraMap.put("sign", sign);
        String data = mapToXml(paraMap);
        log.info("微信公众号请求报文:{}", data);
        //请求微信支付api完成支付
        Map<String, Object> resultMap = WeixinConfigUtil.httpXmlRequest(CommonWeixinProperties.unifiedorder_url, "POST", data);
        System.out.println(resultMap);
        log.info("微信公众号返回报文:{}", resultMap);
        if (resultMap == null || resultMap.isEmpty()||resultMap.get("return_msg")=="fail") {
            return null;
        }else{
            String prepay_id = resultMap.get("prepay_id").toString();
            SortedMap<String, Object> responseMap = new TreeMap<>();
            SortedMap<String, Object> responseMap1 = new TreeMap<>();
            responseMap.putAll(resultMap);
            String resultSign = getSign(responseMap, CommonWeixinProperties.PARTNER_KEY);
            if (resultSign.equals(resultMap.get("sign"))) {
                //   responseMap.put("verify", "YES");
                responseMap1.put("appId", CommonWeixinProperties.component_appid);
                responseMap1.put("timeStamp", System.currentTimeMillis());
                responseMap1.put("nonceStr", getnonceStr());
                responseMap1.put("signType", "MD5");
                responseMap1.put("package", "prepay_id=" + prepay_id);
                String paySign = getSign(responseMap1, CommonWeixinProperties.PARTNER_KEY);
                responseMap1.put("paySign", paySign);
                //logger.info("prepay_id-->",prepay_id);
            } else {
                log.info("返回报文验签失败,返回报文签名:{},返回签名:{}", resultSign, resultMap.get("sign"));
                responseMap1.put("verify", "NO");
            }
            return responseMap1;
        }


    }

    /**
     * 异步通知方法
     * @param notifyMap
     * @return
     */
    public String payBack(Map notifyMap ) {
        log.info("payBack()异步回调微信返回信息", notifyMap);
        String xmlBack="";
        try {
            if (PayUtils.isPayResultNotifySignatureValid(notifyMap)) {
                // 签名正确   进行处理。
                // 注意特殊情况：订单已经退款，但收到了支付结果成功的通知，不应把商户侧订单状态从退款改成支付成功
                String return_code = notifyMap.get("return_code").toString();//通知结果
                String result_code = notifyMap.get("result_code").toString();//业务结果
                String out_trade_no = notifyMap.get("out_trade_no").toString();//订单号
                String total_fee = notifyMap.get("total_fee").toString();//微信返回的订单金额
                String time_end = notifyMap.get("time_end").toString();//支付成功完成时间
                BigDecimal bigDecimal=new BigDecimal(BigInteger.ZERO);
                CourseOrder rpTradePaymentRecord = this.findByNo(out_trade_no);
                if(rpTradePaymentRecord!=null){
                    BigDecimal orderAmount = new BigDecimal(rpTradePaymentRecord.getTotalMoney());
                    bigDecimal = orderAmount.multiply(new BigDecimal(100));
                    //平台金额
                }
                    /*、签名验证 并校验返回的订单金额是否与商户侧的订单金额一致，
                      2、当收到通知进行处理时，首先检查对应业务数据的状态，判断该通知是否已经处理过，如果没有处理过再进行处理，
                         如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前*/
                if(!return_code.equals("SUCCESS")){
                    log.error("微信支付回调通知return_code错误");
                    xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[FAIL]]></return_msg>" + "</xml> ";
                }else{
                    if(!result_code.equals("SUCCESS")){
                        log.error("微信支付回调通知result_code错误");
                        xmlBack = "<xml>" + "<result_code><![CDATA[FAIL]]></result_code>" + "<return_msg><![CDATA[FAIL]]></return_msg>" + "</xml> ";

                    }else{
                        if(bigDecimal.compareTo (new BigDecimal(total_fee))!=0){
                            log.error("金额不一致");
                            xmlBack = "<xml>" + "<result_code><![CDATA[FAIL]]></result_code>" + "<return_msg><![CDATA[FAIL]]></return_msg>" + "</xml> ";
                        }else {
                            Integer status = rpTradePaymentRecord.getPayStatus();//平台订单状态
                            if(!status.equals(2)){
                                //更新状态

                                //dao.updateGoodLst(2,String.valueOf(new Date()),sdf(time_end),out_trade_no);
                                productDetailsDao.updateUseStatus(1,out_trade_no );
                                CourseOrder courseOrder = dao.findByNo(out_trade_no);
                                courseOrder.setPayStatus(2);
                                courseOrder.setUpdateDate(String.valueOf(new Date()));
                                courseOrder.setSuccessTime(sdf(time_end));
                                dao.update(courseOrder);
                                CustomerCoupon customerCoupon = customerCouponDao.get(courseOrder.getCouponId());
                                customerCoupon.setUseStatus("1");
                                customerCouponDao.update(customerCoupon);
                                log.info("微信支付回调成功,更新成功: {}", notifyMap);
                                xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                                //告诉微信服务器收到信
                                // 息了，不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
                            }
                            else {
                                log.info("微信支付回调成功订单号: {}", notifyMap);
                                xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                                //告诉微信服务器收到信息了，不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
                            }
                        }
                    }
                }
            } else {
                log.error("微信支付回调通知签名错误");
                xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            }
        } catch (Exception e) {
            log.error("微信支付回调通知失败",e);
            xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        return xmlBack;
    }

    //微信主动查询，返回查询实体对象
    public F2FQueryVo queryJsapi(String orderNo) throws ParseException {
        //调用查询接口，查询支付状态，根据状态改变订单表，记录表
        F2FQueryVo f2FQueryVo = queryWx(orderNo);
        if(f2FQueryVo.getStatus().equals("SUCCESS")){
            //更新状态为成功  更新订单信息（支付状态、支付成功时间）更新订单详情信息（状态为可用1 ）
            //dao.updateGoodLst(2,String.valueOf(new Date()),sdf(f2FQueryVo.getCompleteTime()),orderNo);
            CourseOrder courseOrder = dao.findByNo(orderNo);
            courseOrder.setPayStatus(2);
            courseOrder.setUpdateDate(String.valueOf(new Date()));
            courseOrder.setSuccessTime(sdf(f2FQueryVo.getCompleteTime()));
            dao.update(courseOrder);
            productDetailsDao.updateUseStatus(1,orderNo );
            CustomerCoupon customerCoupon = customerCouponDao.get(courseOrder.getCouponId());
            customerCoupon.setUseStatus("1");
            customerCouponDao.update(customerCoupon);
        }else{
            //更新状态为失败
            dao.updateGoodLst(3,DateUtil.dateToString(new Date(), DATETIME_PATTERN),null,orderNo);
        }
        return f2FQueryVo;
    }


    /**
     * 微信查询订单支付状态
     * @param orderNo
     * @return
     */
    public F2FQueryVo queryWx(String orderNo) throws ParseException {
        CourseOrder rpTradePaymentRecord =null;
        //查询订单queryOrder,输入订单号，查询订单号存在于平台？
        SortedMap<String, Object> data = new TreeMap<>();
        if (orderNo != null){//如果商户订单号不为空
            rpTradePaymentRecord = this.findByNo(orderNo);
            if (null != rpTradePaymentRecord.getId()) {
                data.put("out_trade_no", orderNo);//
            }
        }
        SortedMap wxResultMap= queryOrder(data);
        System.out.println("wxResultMap:" + wxResultMap);
        /*微信支付订单api请求返回结果
          说明以下字段在return_code 、result_code、trade_state都为SUCCESS时有返回 ，
          如trade_state不为 SUCCESS，则只返回out_trade_no（必传）和attach（选传）
          trade_state值为(   SUCCESS—支付成功
                            REFUND—转入退款
                            NOTPAY—未支付
                            CLOSED—已关闭
                            REVOKED—已撤销(刷卡支付)
                            USERPAYING--用户支付中
                            PAYERROR--支付失败(其他原因，如银行返回失败))
        */
        String msg = "";
        //订单支付成功
        String return_code = wxResultMap.get("return_code").toString();
        String result_code = wxResultMap.get("result_code").toString();
        if (return_code.equals("SUCCESS") && result_code.equals("FAIL")) {
            msg = "订单不存在";
            wxResultMap.put("status","ORDERNOTEXIST");
        } else {
            String trade_state = wxResultMap.get("trade_state").toString();
            if (trade_state.equals("SUCCESS")) {
                msg = "微信支付成功，查询成功";
                String time_end = wxResultMap.get("time_end").toString();
                return new F2FQueryVo(wxResultMap.get("transaction_id").toString(), wxResultMap.get("openid").toString(), BigDecimal.valueOf(Long.valueOf(wxResultMap.get("total_fee").toString())),  time_end, wxResultMap.get("trade_state").toString(), wxResultMap.get("out_trade_no").toString(), msg);
            } else {
                msg = "微信支付状态未知";
            }
        }
        return new F2FQueryVo(wxResultMap.get("transaction_id") == null ?
                null : wxResultMap.get("transaction_id").toString(),
                wxResultMap.get("openid") == null ? null : wxResultMap.get("openid").toString(),
                new BigDecimal(wxResultMap.get("total_fee") == null ? "0" : wxResultMap.get("total_fee").toString()),
                null == wxResultMap.get("time_end") ? null :  wxResultMap.get("time_end").toString() ,
                wxResultMap.get("trade_state") == null ? null : wxResultMap.get("trade_state").toString(),
                wxResultMap.get("out_trade_no") == null ? null : wxResultMap.get("out_trade_no").toString(), msg);
    }
    /**
     *  微信公众号支付订单查询
     */
    public static SortedMap queryOrder(SortedMap map) {
        SortedMap  data = new TreeMap();
        //检测必填参数
        if (map.get("out_trade_no")==null) {
            log.info("订单查询接口中，缺少必填参数out_trade_no", "a1");
            data.put("out_trade_no","订单号为空");
            return data;
        }
        map.put("appid", WeixinConfigUtil.appid);//公众账号ID
        map.put("mch_id", WeixinConfigUtil.mchid);//商户号
        map.put("nonce_str", getnonceStr());//随机字符串
        //map.put("sub_mch_id", sub_mch_id);//服务商模式必传子商户号
        map.put("sign",getSign(map, WeixinConfigUtil.partnerKey));//签名
        String xml = mapToXml(map);
        try {
            try {
                data = new HttpsRequest().sendPostl(WeixinConfigUtil.query_url, xml);
            } catch (DocumentException e) {
                e.printStackTrace();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }
        return data;
    }

     public String sdf(String endTime) throws ParseException {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
         Date parse = sdf.parse(endTime);
         SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         String format = fmt.format(parse);
         return format;
     }

    /**
     * 根据参数获取订单交易总额
     * @param courseOrder
     * @return
     */
     public String findSumByParam(CourseOrder courseOrder) {
         CourseOrder order = dao.findSumByParam(courseOrder);
         String totalMoney = "0";
         if(order != null) {
             totalMoney = order.getTotalMoney();
         }
        return totalMoney;
     }
}
